#include "clogic.h"
void CLogic::setNetPackMap()
{
    NetPackMap(_DEF_PACK_REGISTER_RQ) = &CLogic::RegisterRq;          // 注册请求
    NetPackMap(_DEF_PACK_LOGIN_RQ) = &CLogic::LoginRq;                // 登录请求
    NetPackMap(_DEF_PACK_FILE_LIST_RQ) = &CLogic::UserFileListRq;     // 获取用户文件列表请求
    NetPackMap(_DEF_PACK_FILE_DOWNLOAD_RQ) = &CLogic::DownloadFileRq; // 下载请求
    NetPackMap(_DEF_PACK_FILE_HEAD_RS) = &CLogic::FileHeadRs;         // 文件头回复
    NetPackMap(_DEF_PACK_FILE_CONTENT_RS) = &CLogic::FileContentRs;   // 文件内容回复
    NetPackMap(_DEF_PACK_UPLOAD_FILE_RQ) = &CLogic::UploadFileRq;     // 上传文件请求
    NetPackMap(_DEF_PACK_FILE_CONTENT_RQ) = &CLogic::FileContentRq;   // 文件块请求
    NetPackMap(_DEF_PACK_ADD_FOLDER_RQ) = &CLogic::AddFolderRq;       // 新建文件夹请求
    NetPackMap(_DEF_PACK_DELETE_FILE_RQ) = &CLogic::DeleteFileRq;     // 删除文件请求
    NetPackMap(_DEF_PACK_SHARE_FILE_RQ) = &CLogic::ShareFileRq;       // 分享文件请求
    NetPackMap(_DEF_PACK_MY_SHARE_RQ) = &CLogic::MyShareRq;           // 获取我的共享
    NetPackMap(_DEF_PACK_GET_SHARE_RQ) = &CLogic::GetShareFile;       // 获取文件请求
    NetPackMap(_DEF_PACK_CONTINUE_DOWNLOAD_RQ) = &CLogic::ContinueDownloadRq;
    NetPackMap(_DEF_PACK_CONTINUE_UPLOAD_RQ) = &CLogic::ContinueUploadRq;
}
// 注册
void CLogic::RegisterRq(sock_fd clientfd, char *szbuf, int nlen)
{
    printf("clientfd:%d RegisterRq\n", clientfd);
    // 拆包 tel passwd name
    STRU_REGISTER_RQ *rq = (STRU_REGISTER_RQ *)szbuf;
    // 查数据库
    STRU_REGISTER_RS rs;
    char sqlbuf[1000] = "";
    list<string> lstRes;
    sprintf(sqlbuf, "select u_tel from t_user where u_tel='%s';", rq->tel);
    bool res = m_sql->SelectMysql(sqlbuf, 1, lstRes);
    if (!res)
    {
        printf("sql select error:%s\n", sqlbuf);
        return;
    }
    // 有->手机号已存在
    if (lstRes.size() > 0)
    {
        rs.result = tel_is_exist;
    }
    else
    {
        // 没有 查数据库 条件name 看昵称是否存在
        sprintf(sqlbuf, "select u_name from t_user where u_name='%s';", rq->name);
        lstRes.clear();
        res = m_sql->SelectMysql(sqlbuf, 1, lstRes);
        if (!res)
        {
            printf("sql select error:%s\n", sqlbuf);
            return;
        }
        // 名字存在 返回name_is_exist;
        if (lstRes.size() > 0)
        {
            rs.result = name_is_exist;
        }
        // 昵称不存在 注册成功 数据库插入信息
        else
        {

            sprintf(sqlbuf, "insert into t_user(u_tel,u_password,u_name)values('%s','%s','%s');", rq->tel, rq->password, rq->name);
            res = m_sql->UpdataMysql(sqlbuf);
            if (!res)
            {
                printf("sql update error:%s\n", sqlbuf);
                return;
            }
            // 网盘创建存储路径/home/linux/MyServer/NetDisk_Data/usr_id
            sprintf(sqlbuf, "select u_id from t_user where u_tel='%s';", rq->tel);
            lstRes.clear();
            res = m_sql->SelectMysql(sqlbuf, 1, lstRes);
            int id = 0;
            if (lstRes.size() > 0)
            {
                id = atoi(lstRes.front().c_str());
            }
            char strPath[260] = "";
            sprintf(strPath, "%s/%d", DEF_PATH, id);
            umask(0);
            mkdir(strPath, S_IRWXU | S_IRWXG | S_IRWXO);
            // 拥有者，组，其他组，读写执行权限
            rs.result = register_success;
        }
    }
    // 发送回复包
    SendData(clientfd, (char *)&rs, sizeof(rs));
}
// 登录
void CLogic::LoginRq(sock_fd clientfd, char *szbuf, int nlen)
{
    printf("clientfd:%d LoginRq\n", clientfd);
    // 拆包
    STRU_LOGIN_RQ *rq = (STRU_LOGIN_RQ *)szbuf;
    STRU_LOGIN_RS rs;
    // 查看数据库 where 手机号,查passwd,id，name
    char sqlstr[1000] = "";
    list<string> lstRes;
    sprintf(sqlstr, "select u_password,u_id,u_name from t_user where u_tel='%s';", rq->tel);
    m_sql->SelectMysql(sqlstr, 3, lstRes);
    // 没有结果->手机号不存在
    if (lstRes.size() == 0)
    {
        rs.result = tel_not_exist;
    }
    // 有结果
    else
    {
        // 比较密码是否一致
        if (strcmp(rq->password, lstRes.front().c_str()) != 0)
        {
            // 否->密码错误
            rs.result = password_error;
        }
        else
        {
            lstRes.pop_front();
            // 是 回复包里写 id name
            int id = atoi(lstRes.front().c_str());
            lstRes.pop_front();
            string name = lstRes.front();

            rs.userid = id;
            strcpy(rs.name, name.c_str());
            rs.result = login_success;
            // map[id]=UserInfo id 对用户信息的映射关系
            UserInfo *u_info;
            if (!m_mapIDToUserInfo.find(id, u_info))
            {
                u_info = new UserInfo;
            }
            else
            {
                // 踢掉原来的用户
                // 通过协议包，给一号客户端发个协议包，客户端收到就执行退出回收
            }
            u_info->name = name;
            u_info->userid = id;
            u_info->clientfd = clientfd;
            // 更新映射关系
            m_mapIDToUserInfo.insert(id, u_info);
        }
    }
    // 发送回复包
    SendData(clientfd, (char *)&rs, sizeof(rs));
}
// 用户文件列表请求
void CLogic::UserFileListRq(sock_fd clientfd, char *szbuf, int nlen)
{
    // 拆包
    STRU_FILE_LIST_RQ *rq = (STRU_FILE_LIST_RQ *)szbuf;
    // 获取路径和userid 查数据库 找到文件信息
    char sqlbuf[1024] = "";
    sprintf(sqlbuf, "select f_id, f_name, f_uploadtime, f_size, f_MD5, f_type from t_file where f_id in (select f_id  from  t_user_file  where f_dir = '%s'and u_id = %d);", rq->dir, rq->userid);
    list<string> lstRes;
    bool res = m_sql->SelectMysql(sqlbuf, 6, lstRes);
    if (!res)
    {
        printf("select error sql:%s", sqlbuf);
        return;
    }
    if (lstRes.size() == 0)
    {
        return;
    }
    // 封包循环发送文件信息
    while (lstRes.size() != 0)
    {
        // 读数据str_uploadtime
        string str_id = lstRes.front();
        lstRes.pop_front();
        string str_name = lstRes.front();
        lstRes.pop_front();
        string str_uploadtime = lstRes.front();
        lstRes.pop_front();
        string str_size = lstRes.front();
        lstRes.pop_front();
        string str_md5 = lstRes.front();
        lstRes.pop_front();
        string str_type = lstRes.front();
        lstRes.pop_front();
        // 封包
        STRU_FILE_INFO info;
        info.userid = rq->userid;
        info.fileid = atoi(str_id.c_str());
        strcpy(info.dir, rq->dir);
        strcpy(info.md5, str_md5.c_str());
        info.size = atoi(str_size.c_str());
        strcpy(info.fileName, str_name.c_str());
        strcpy(info.filetype, str_type.c_str());
        strcpy(info.uploadTime, str_uploadtime.c_str());
        // 发送数据包
        SendData(clientfd, (char *)&info, sizeof(info));
    }
}
// 处理下载请求
void CLogic::DownloadFileRq(sock_fd clientfd, char *szbuf, int nlen)
{
    // /
    printf("clientfd:%d DownloadFileRq\n", clientfd);
    // 拆包
    STRU_DOWNLOAD_RQ *rq = (STRU_DOWNLOAD_RQ *)szbuf; //
    // 查数据库,根据类型进行不同流程
    char sqlbuf[1000] = "";
    sprintf(sqlbuf, "select f_type, t_file.f_id, f_name, f_md5, f_size, t_user_file.f_dir, f_path \
    from t_file inner join t_user_file on t_file.f_id = t_user_file.f_id where t_user_file.u_id = %d and t_file.f_id = %d and t_user_file.f_dir='%s';",
            rq->userid, rq->fileid, rq->dir);
    // sprintf(sqlbuf, "select *from user_file_info where u_id = %d and f_id = %d and f_dir = '%s';", rq->userid, rq->fileid, rq->dir);

    list<string> lstRes;
    // list<string> lst = lstRes;
    m_sql->SelectMysql(sqlbuf, 7, lstRes);
    if (lstRes.size() == 0)
    {
        // 下载失败
        printf("DownloadFileRq failed\n");
        return;
    }
    // printf("列表长:%d\n", lstRes.size());
    //  文件
    if (lstRes.front() == "file")
    {
        //  做映射   fileid->FileInfo
        FileInfo *info = new FileInfo;
        info->type = lstRes.front();
        lstRes.pop_front();
        info->fileid = atoi(lstRes.front().c_str());
        lstRes.pop_front();
        info->name = lstRes.front();
        lstRes.pop_front();
        info->md5 = lstRes.front();
        lstRes.pop_front();
        info->size = atoi(lstRes.front().c_str());
        lstRes.pop_front();
        info->dir = lstRes.front();
        lstRes.pop_front();
        info->absolutePath = lstRes.front();
        lstRes.pop_front();
        lstRes.clear();
        info->filefd = open(info->absolutePath.c_str(), O_RDONLY);
        if (info->filefd <= 0)
        {
            std::cout << "file open failed" << info->filefd << std::endl;
        }
        char idbuf[100] = "";
        sprintf(idbuf, "%10d%10d", rq->userid, rq->fileid);
        string strid = idbuf;
        m_mapFileidToFileInfo.insert(strid, info);
        // 单独的文件下载
        STRU_FILE_HEAD_RQ headrq;
        strcpy(headrq.dir, info->dir.c_str()); // 带文件夹的下载，需要dir
        headrq.fileid = info->fileid;
        strcpy(headrq.fileName, info->name.c_str());
        strcpy(headrq.fileType, info->type.c_str());
        strcpy(headrq.md5, info->md5.c_str());
        headrq.size = info->size;
        headrq.flag = true;
        // 返回文件头请求
        SendData(clientfd, (char *)&headrq, sizeof(headrq));
    }
    // if (info->type == "file")
    // {
    //     DownloadFile(clientfd, rq->userid, lst);
    // }
    else
    {
        // 下载文件夹,包含内部的文件
        list<string>::iterator ite = lstRes.begin();
        ite++;
        ite++;
        string name = (*ite);
        // printf("name_:%s\n", name.c_str());
        DownloadFolder(clientfd, rq->userid, rq->fileid, name, rq->dir);
        // delete info;
    }
}

// 处理文件头回复
void CLogic::FileHeadRs(sock_fd clientfd, char *szbuf, int nlen)
{
    printf("clientfd:%d FileHeadRs\n", clientfd);
    // printf("clientfd:%d FileHeadRs\n", clientfd);
    //  拆包
    STRU_FILE_HEAD_RS *rs = (STRU_FILE_HEAD_RS *)szbuf;
    // 取出信息
    FileInfo *info = nullptr;
    char idbuf[100];
    sprintf(idbuf, "%10d%10d", rs->userid, rs->fileid);
    // 从map找文件
    if (!m_mapFileidToFileInfo.find(idbuf, info))
    {
        std::cout << "file not find" << std::endl;
        return;
    }
    // 读取文件
    STRU_FILE_CONTENT_RQ rq;
    rq.fileid = rs->fileid;
    rq.userid = rs->userid;
    rq.len = read(info->filefd, rq.content, _DEF_BUFFER);
    // 发送文件内容
    SendData(clientfd, (char *)&rq, sizeof(rq));
}
// 处理文件块回复
void CLogic::FileContentRs(sock_fd clientfd, char *szbuf, int nlen)
{
    // printf("clientfd:%d FileContentRs\n", clientfd);
    //  拆包
    STRU_FILE_CONTENT_RS *rs = (STRU_FILE_CONTENT_RS *)szbuf;
    // 取出信息
    FileInfo *info = nullptr;
    char idbuf[100];
    sprintf(idbuf, "%10d%10d", rs->userid, rs->fileid);
    // 从map找文件
    if (!m_mapFileidToFileInfo.find(idbuf, info))
    {
        std::cout << "file not find" << std::endl;
        return;
    }
    // 如果不成功 文件流会跳到之前的位置, 重新读TODO
    if (rs->result == 0)
    {
        lseek(info->filefd, -1 * (rs->len), SEEK_CUR);
    }
    // 成功
    else
    {
        info->pos += rs->len; // pos+len
        // 读取到文件尾,读取结束
        if (info->pos >= info->size)
        {
            close(info->filefd);                // 关闭文件描述符
            m_mapFileidToFileInfo.erase(idbuf); // 回收节点
            delete info;
        }
    }
    // 读取文件
    STRU_FILE_CONTENT_RQ rq;
    rq.fileid = rs->fileid;
    rq.userid = rs->userid;
    rq.len = read(info->filefd, rq.content, _DEF_BUFFER);
    // 发送文件内容
    SendData(clientfd, (char *)&rq, sizeof(rq));
}
// 处理上传文件请求
void CLogic::UploadFileRq(sock_fd clientfd, char *szbuf, int nlen)
{
    printf("clientfd:%d UploadFileRq\n", clientfd);
    // 拆包
    STRU_UPLOAD_FILE_RQ *rq = (STRU_UPLOAD_FILE_RQ *)szbuf;
    // 获取信息
    // 获取路径
    char pathbuf[1024] = "";
    sprintf(pathbuf, "%s/%d%s%s", DEF_PATH, rq->userid, rq->dir, rq->fileName);
    // MD5 看是否秒传,文件名+MD5+state作为条件看是否有秒传
    {
        char sqlbuf[1024] = "";
        sprintf(sqlbuf, "select f_id from t_file where f_name='%s' and f_md5='%s' and f_state=1;", rq->fileName, rq->md5);
        list<string> lstRes;
        m_sql->SelectMysql(sqlbuf, 1, lstRes);
        if (lstRes.size() > 0)
        {
            int fileid = stoi(lstRes.front());
            sprintf(sqlbuf, "insert into t_user_file values(%d,%d,'%s');", rq->userid, fileid, rq->dir);
            if (!m_sql->UpdataMysql(sqlbuf))
            {
                std::cout << "updata dailed" << std::endl;
            }
            // 写回复
            STRU_QUICK_UPLOAD_RS rs;
            rs.fileid = fileid;
            strcpy(rs.md5, rq->md5);
            rs.result = 1;
            rs.userid = rq->userid;
            SendData(clientfd, (char *)&rs, sizeof(rs));
            return;
        }
    }
    // 不是秒传
    // 把文件信息插入到数据库
    char sqlbuf[2048] = "";
    sprintf(sqlbuf, "insert into t_file(f_name,f_uploadtime,f_size,f_path,f_count,f_MD5,f_state, f_type) values('%s','%s', %d,'%s',0,'%s',0,'%s');",
            rq->fileName, rq->time, rq->size, pathbuf, rq->md5, rq->fileType);
    // 把文件信息写入数据库中
    if (!m_sql->UpdataMysql(sqlbuf))
    {
        std::cout << "insert failed" << sqlbuf << std::endl;
    }
    // 查询获取id
    list<string> lstRes;
    sprintf(sqlbuf, "select f_id from t_file where f_name = '%s'and f_md5='%s';", rq->fileName, rq->md5);
    bool res = m_sql->SelectMysql(sqlbuf, 1, lstRes);
    if (!res)
    {
        std::cout << "select failed" << std::endl;
    }
    int strFileid = stoi(lstRes.front());
    lstRes.pop_front();
    // 写数据库->用户文件关系
    sprintf(sqlbuf, "insert into t_user_file(u_id,f_id ,f_dir) value(%d,%d,'%s');", rq->userid, strFileid, rq->dir);
    if (!m_sql->UpdataMysql(sqlbuf))
    {
        std::cout << "insert failed 1" << sqlbuf << std::endl;
    }
    // 打开文件
    std::cout << pathbuf << std::endl;
    int tmpFilefd = open(pathbuf, O_CREAT | O_WRONLY | O_TRUNC, 0777);

    if (tmpFilefd <= 0)
    {
        std::cout << "file create failed" << std::endl;
    }
    // 创建文件信息结构体
    FileInfo *info = new FileInfo;
    info->absolutePath = pathbuf;
    info->dir = rq->dir;
    info->md5 = rq->md5;
    info->name = rq->fileName;
    info->size = rq->size;
    info->time = rq->time;
    info->type = rq->fileType;
    info->fileid = strFileid;
    info->filefd = tmpFilefd;
    // 添加到map
    char idstr[100] = "";
    sprintf(idstr, "%10d%10d", rq->userid, info->fileid);
    m_mapFileidToFileInfo.insert(idstr, info);
    // 写回复
    STRU_UPLOAD_FILE_RS rs;
    rs.fileid = info->fileid;
    rs.userid = rq->userid;
    rs.result = 1; // 默认成功
    strcpy(rs.md5, rq->md5);
    SendData(clientfd, (char *)&rs, sizeof(rs));
}
// 处理上传文件块请求
void CLogic::FileContentRq(sock_fd clientfd, char *szbuf, int nlen)
{
    // printf("clientfd:%d FileContentRq\n", clientfd);
    //   拆包
    STRU_FILE_CONTENT_RQ *rq = (STRU_FILE_CONTENT_RQ *)szbuf;
    // 从map中获取对应的文件信息结构体
    char idbuf[100] = "";
    sprintf(idbuf, "%10d%10d", rq->userid, rq->fileid);
    FileInfo *info = nullptr;
    if (!m_mapFileidToFileInfo.find(idbuf, info))
    {
        std::cout << "map not find key" << std::endl;
        return;
    }
    // 写入内容
    STRU_FILE_CONTENT_RS rs;
    int len = write(info->filefd, rq->content, rq->len);
    // 失败,写入的和要写的不一致
    if (len != rq->len)
    {
        lseek(info->filefd, -1 * len, SEEK_CUR);
        rs.result = 0;
    }
    // 成功
    else
    {
        rs.result = 1;
        info->pos += len;
        // 判断是否结束
        if (info->pos >= info->size)
        {
            // 结束关闭文件 回收 数据库状态->1
            close(info->filefd);
            m_mapFileidToFileInfo.erase(idbuf);
            char sqlbuf[1024] = "";
            sprintf(sqlbuf, "update t_file set f_state=1 where f_id=%d;", rq->fileid);
            m_sql->UpdataMysql(sqlbuf);
            delete info;
            info = nullptr;
        }
    }
    // 没结束写回复
    rs.fileid = rq->fileid;
    rs.len = rq->len;
    rs.userid = rq->userid;
    SendData(clientfd, (char *)&rs, sizeof(rs));
}
// 处理新建文件夹请求
void CLogic::AddFolderRq(sock_fd clientfd, char *szbuf, int nlen)
{
    printf("clientfd:%d AddFolderRq\n", clientfd);
    // 拆包
    STRU_ADD_FOLDER_RQ *rq = (STRU_ADD_FOLDER_RQ *)szbuf;
    // 获取信息
    // 获取路径
    int Fileid = 0;
    char pathbuf[1024] = "";
    sprintf(pathbuf, "%s/%d%s%s", DEF_PATH, rq->userid, rq->dir, rq->fileName);
    // MD5 看是否秒传,文件名+MD5+state作为条件看是否有秒传
    // 不是秒传

    // 判断是否存在,有就不插入
    //  查询获取id
    char sqlbuf[2048] = "";
    list<string> lstRes;
    sprintf(sqlbuf, "select f_id from t_file where f_name = '%s' and f_type ='%s';", rq->fileName, "dir");
    bool res = m_sql->SelectMysql(sqlbuf, 1, lstRes);
    if (!res)
    {
        std::cout << "select failed" << std::endl;
    }
    if (lstRes.size() == 0)
    {
        // 把文件夹信息插入到数据库
        sprintf(sqlbuf, "insert into t_file(f_name,f_uploadtime,f_size,f_path,f_count,f_MD5,f_state, f_type) values('%s','%s', %d,'%s',0,'%s',1,'%s');",
                rq->fileName, rq->time, rq->size, pathbuf, rq->md5, rq->fileType);
        // 把文件信息写入数据库中
        if (!m_sql->UpdataMysql(sqlbuf))
        {
            std::cout << "insert failed" << sqlbuf << std::endl;
        }
        // 查询获取id
        lstRes.clear();
        sprintf(sqlbuf, "select f_id from t_file where f_name = '%s'and f_md5='%s';", rq->fileName, rq->md5);
        res = m_sql->SelectMysql(sqlbuf, 1, lstRes);
        if (!res)
        {
            std::cout << "select failed" << std::endl;
        }
        Fileid = stoi(lstRes.front());
        lstRes.pop_front();
    }
    else
    {
        Fileid = stoi(lstRes.front());
        lstRes.pop_front();
    }
    // 写数据库->用户文件关系
    sprintf(sqlbuf, "insert into t_user_file(u_id,f_id ,f_dir) value(%d,%d,'%s');", rq->userid, Fileid, rq->dir);
    if (!m_sql->UpdataMysql(sqlbuf))
    {
        std::cout << "insert failed 1" << sqlbuf << std::endl;
        return;
    }
    // 创建文件夹
    umask(0);
    mkdir(pathbuf, S_IRWXU | S_IRWXG | S_IRWXO);
    // 写回复
    STRU_ADD_FOLDER_RS rs;
    rs.result = 1; // 默认成功
    SendData(clientfd, (char *)&rs, sizeof(rs));
}
// 处理删除文件请求  删除选中的每一项,每一项区分文件或文件夹
void CLogic::DeleteFileRq(sock_fd clientfd, char *szbuf, int nlen)
{
    printf("clientfd:%d DeleteFileRq\n", clientfd);
    // 拆包
    STRU_DELETE_FILE_RQ *rq = (STRU_DELETE_FILE_RQ *)szbuf;
    int n = rq->fileCount;
    // 列表->每一项 u_id f_id f_dir
    for (int i = 0; i < n; ++i)
    {
        // 每一项id->类型
        DeleteItem(rq->userid, rq->fileidArray[i], rq->dir);
    }
    STRU_DELETE_FILE_RS rs;
    strcpy(rs.dir, rq->dir);
    rs.result = 1;
    SendData(clientfd, (char *)&rs, sizeof(rs));
}
// 分享文件请求
void CLogic::ShareFileRq(sock_fd clientfd, char *szbuf, int nlen)
{
    printf("clientfd:%d ShareFileRq\n", clientfd);
    // 拆包
    STRU_SHARE_FILE_RQ *rq = (STRU_SHARE_FILE_RQ *)szbuf;
    // 分享文件需要的 参数+随机数字
    int link = 0;
    do
    {
        link = random() % 9 + 1; // 第一位
        link *= 10000000;
        link += random() % 10000000; // 后7位
        // 与库匹配,去重
        char sqlbuf[1024] = "";
        list<string> lstRes;
        sprintf(sqlbuf, "select s_link from t_shareFile where s_link=%d;", link);
        m_sql->SelectMysql(sqlbuf, 1, lstRes);
        if (lstRes.size() != 0)
        {
            link = 0;
        }
    } while (link == 0);

    int n = rq->itemCount;
    for (int i = 0; i < n; ++i)
    {
        ShareItem(rq->userid, rq->fileidArray[i], rq->dir, rq->shareTime, link);
    }
    // 写回复
    STRU_SHARE_FILE_RS rs;
    rs.result = 1;
    SendData(clientfd, (char *)&rs, sizeof(rs));
}
// 处理我的分享列表请求
void CLogic::MyShareRq(sock_fd clientfd, char *szbuf, int nlen)
{
    printf("clientfd:%d MyShareRq\n", clientfd);

    STRU_MY_SHARE_RQ *rq = (STRU_MY_SHARE_RQ *)szbuf;
    // 联表查询
    char sqlbuf[1024] = "";
    sprintf(sqlbuf, "select f_name,f_size,s_linkTime,s_link from share_file_info where u_id=%d;", rq->userid);
    list<string> lstRes;
    m_sql->SelectMysql(sqlbuf, 4, lstRes);
    int len = sizeof(STRU_MY_SHARE_RS) + sizeof(MY_SHARE_FILE) * (lstRes.size() / 4);
    STRU_MY_SHARE_RS *rs = (STRU_MY_SHARE_RS *)malloc(len);
    rs->init();
    rs->itemCount = lstRes.size() / 4;
    int count = 0;
    while (lstRes.size() != 0)
    {
        string name = lstRes.front();
        lstRes.pop_front();

        int size = stoi(lstRes.front());
        lstRes.pop_front();

        string time = lstRes.front();
        lstRes.pop_front();

        int link = stoi(lstRes.front());
        lstRes.pop_front();

        strcpy(rs->items[count].name, name.c_str());
        rs->items[count].size = size;
        strcpy(rs->items[count].time, time.c_str());
        rs->items[count].shareLink = link;
        count++;
    }
    // 写回复
    SendData(clientfd, (char *)rs, len);
}

void CLogic::GetShareFile(sock_fd clientfd, char *szbuf, int nlen)
{
    printf("clientfd:%d GetShareFile\n", clientfd);
    STRU_GET_SHARE_RQ *rq = (STRU_GET_SHARE_RQ *)szbuf;
    // 查数据库
    char sqlbuf[1024] = "";
    sprintf(sqlbuf, "select u_id,f_id,f_dir,f_type,f_name from share_file_info where s_link=%d;", rq->shareLink);
    list<string> lstRes;
    m_sql->SelectMysql(sqlbuf, 5, lstRes);
    // 看是否为文件(夹)
    while (lstRes.size() != 0)
    {
        int from_userid = stoi(lstRes.front());
        lstRes.pop_front();
        int fileid = stoi(lstRes.front());
        lstRes.pop_front();
        string from_dir = lstRes.front();
        lstRes.pop_front();
        string type = lstRes.front();
        lstRes.pop_front();
        string name = lstRes.front();
        lstRes.pop_front();

        // 将文件添加到用户关系表中
        if (type == "file")
        {
            GetShareByFile(rq->userid, fileid, rq->dir);
        }
        else
        {
            GetShareByFolder(rq->userid, fileid, rq->dir, from_userid, from_dir, name);
        }
    }
    // 写回复
    STRU_GET_SHARE_RS rs;
    strcpy(rs.dir, rq->dir);
    rs.result = 1;
    SendData(clientfd, (char *)&rs, sizeof(rs));
}
void CLogic::ContinueDownloadRq(sock_fd clientfd, char *szbuf, int nlen)
{
    printf("clinet:%d,ContinueDownloadRq\n", clientfd);
    // 拆包
    STRU_CONTINUE_DOWNLOAD_RQ *rq = (STRU_CONTINUE_DOWNLOAD_RQ *)szbuf;
    // 看map中有没有
    FileInfo *info = nullptr;
    char idbuf[100];
    sprintf(idbuf, "%10d%10d", rq->userid, rq->fileid);
    if (!m_mapFileidToFileInfo.find(idbuf, info))
    {
        // 没有创建info 填写内容
        info = new FileInfo;
        char sqlbuf[1000] = "";
        sprintf(sqlbuf, "select f_type, t_file.f_id, f_name, f_md5, f_size, t_user_file.f_dir, f_path \
    from t_file inner join t_user_file on t_file.f_id = t_user_file.f_id where t_user_file.u_id = %d and t_file.f_id = %d and t_user_file.f_dir='%s';",
                rq->userid, rq->fileid, rq->dir);
        // sprintf(sqlbuf, "select *from user_file_info where u_id = %d and f_id = %d and f_dir = '%s';", rq->userid, rq->fileid, rq->dir);

        list<string> lstRes;
        // list<string> lst = lstRes;
        m_sql->SelectMysql(sqlbuf, 7, lstRes);
        if (lstRes.size() == 0)
        {
            // 下载失败
            printf("DownloadFileRq failed\n");
            return;
        }
        info->type = lstRes.front();
        lstRes.pop_front();
        info->fileid = atoi(lstRes.front().c_str());
        lstRes.pop_front();
        info->name = lstRes.front();
        lstRes.pop_front();
        info->md5 = lstRes.front();
        lstRes.pop_front();
        info->size = atoi(lstRes.front().c_str());
        lstRes.pop_front();
        info->dir = lstRes.front();
        lstRes.pop_front();
        info->absolutePath = lstRes.front();
        lstRes.pop_front();
        lstRes.clear();
        info->filefd = open(info->absolutePath.c_str(), O_RDONLY);
        if (info->filefd <= 0)
        {
            std::cout << "file open failed" << info->filefd << std::endl;
        }
        char idbuf[100] = "";
        sprintf(idbuf, "%10d%10d", rq->userid, rq->fileid);
        string strid = idbuf;
        m_mapFileidToFileInfo.insert(strid, info);
    }
    // 跳转pos
    lseek(info->filefd, rq->pos, SEEK_CUR);
    info->pos = rq->pos;
    // 有
    // 读取文件
    STRU_FILE_CONTENT_RQ contentRq;
    contentRq.fileid = rq->fileid;
    contentRq.userid = rq->userid;
    contentRq.len = read(info->filefd, contentRq.content, _DEF_BUFFER);
    // 发送文件内容
    SendData(clientfd, (char *)&contentRq, sizeof(contentRq));
}
void CLogic::ContinueUploadRq(sock_fd clientfd, char *szbuf, int nlen)
{
    // 拆包
    STRU_CONTINUE_UPLOAD_RQ *rq = (STRU_CONTINUE_UPLOAD_RQ *)szbuf;
    // map
    FileInfo *info = nullptr;
    char idbuf[100];
    sprintf(idbuf, "%10d%10d", rq->userid, rq->fileid);
    if (!m_mapFileidToFileInfo.find(idbuf, info))
    {
        // 没有
        //  没有创建info 填写内容
        info = new FileInfo;
        char sqlbuf[1000] = "";
        sprintf(sqlbuf, "select f_type, t_file.f_id, f_name, f_md5, f_size, t_user_file.f_dir, f_path \
    from t_file inner join t_user_file on t_file.f_id = t_user_file.f_id where t_user_file.u_id = %d and t_file.f_id = %d and t_user_file.f_dir='%s';",
                rq->userid, rq->fileid, rq->dir);
        // sprintf(sqlbuf, "select *from user_file_info where u_id = %d and f_id = %d and f_dir = '%s';", rq->userid, rq->fileid, rq->dir);
        
        list<string> lstRes;
        
        // list<string> lst = lstRes;
        m_sql->SelectMysql(sqlbuf, 7, lstRes);
        if (lstRes.size() == 0)
        {
            // 下载失败
            printf("failed\n");
            return;
        }
        info->type = lstRes.front();
        lstRes.pop_front();
        info->fileid = atoi(lstRes.front().c_str());
        lstRes.pop_front();
        info->name = lstRes.front();
        lstRes.pop_front();
        info->md5 = lstRes.front();
        lstRes.pop_front();
        info->size = atoi(lstRes.front().c_str());
        lstRes.pop_front();
        info->dir = lstRes.front();
        lstRes.pop_front();
        info->absolutePath = lstRes.front();
        lstRes.pop_front();
        lstRes.clear();
        info->filefd = open(info->absolutePath.c_str(), O_WRONLY);
        if (info->filefd <= 0)
        {
            std::cout << "file open failed" << info->filefd << std::endl;
        }
        char idbuf[100] = "";
        sprintf(idbuf, "%10d%10d", rq->userid, rq->fileid);
        string strid = idbuf;

        info->pos = lseek(info->filefd, 0, SEEK_END);
        m_mapFileidToFileInfo.insert(strid, info);
    }
    STRU_CONTINUE_UPLOAD_RS rs;
    rs.fileid = rq->fileid;
    rs.pos = info->pos;
    SendData(clientfd, (char *)&rs, sizeof(rs));
}
// 删除每一项
void CLogic::DeleteItem(int userid, int fileid, string dir)
{
    // 判断是文件还是文件夹
    // select f_id , f_name , f_count , f_path , f_dir , f_type from user_file_info where u_id = %d and f_id = %d and f_dir = '%s';
    char sqlbuf[1024] = "";
    sprintf(sqlbuf, "select f_id , f_name ,f_count,f_path,f_dir,f_type from user_file_info where u_id = %d and f_id = %d and f_dir = '%s';", userid, fileid, dir.c_str());
    list<string> lstRes;
    m_sql->SelectMysql(sqlbuf, 6, lstRes);
    if (lstRes.size() == 0)
    {
        return;
    }
    while (lstRes.size() != 0)
    {
        int fileid = stoi(lstRes.front());
        lstRes.pop_front();
        string name = lstRes.front();
        lstRes.pop_front();
        int count = stoi(lstRes.front());
        lstRes.pop_front();
        string path = lstRes.front();
        lstRes.pop_front();
        string newdir = lstRes.front(); // /1/
        lstRes.pop_front();
        string type = lstRes.front();
        lstRes.pop_front();

        if (type == "file")
        {
            DeleteFile(userid, fileid, name, count, path, newdir);
        }
        else
        {
            DeleteFolder(userid, fileid, name, count, path, newdir);
        }
    }
}
// 本地删除文件,取消数据库关系,文件引用计数为0则从本地删除
void CLogic::DeleteFile(int userid, int fileid, string name, int count, string path, string newdir)
{
    // 清楚数据库关系
    char sqlbuf[1024] = "";
    sprintf(sqlbuf, "delete from t_user_file where u_id=%d and f_id=%d and f_dir='%s';", userid, fileid, newdir.c_str());
    m_sql->UpdataMysql(sqlbuf);
    // count==1 本地删除
    if (count == 1)
    {
        unlink(path.c_str());
    }
    //
}

void CLogic::DeleteFolder(int userid, int fileid, string name, int count, string path, string newdir)
{
    // 清楚数据库关系
    char sqlbuf[1024] = "";
    sprintf(sqlbuf, "delete from t_user_file where u_id=%d and f_id=%d and f_dir='%s';", userid, fileid, newdir.c_str());
    m_sql->UpdataMysql(sqlbuf);
    // 不能删文件夹

    // 判别文件夹里的文件
    {
        char sqlbuf[1024] = "";
        string strDir = newdir + name + "/";
        sprintf(sqlbuf, "select f_id , f_name ,f_count,f_path,f_dir,f_type from user_file_info where u_id = %d  and f_dir = '%s';", userid, strDir.c_str());
        list<string> lstRes;
        m_sql->SelectMysql(sqlbuf, 6, lstRes);
        if (lstRes.size() == 0)
        {
            return;
        }
        while (lstRes.size() != 0)
        {
            int fileid = stoi(lstRes.front());
            lstRes.pop_front();
            string name = lstRes.front();
            lstRes.pop_front();
            int count = stoi(lstRes.front());
            lstRes.pop_front();
            string path = lstRes.front();
            lstRes.pop_front();
            string newdir = lstRes.front();
            lstRes.pop_front();
            string type = lstRes.front();
            lstRes.pop_front();
            if (type == "file")
            {
                DeleteFile(userid, fileid, name, count, path, newdir);
            }
            else
            {
                DeleteFolder(userid, fileid, name, count, path, newdir);
            }
        }
    }
}

void CLogic::ShareItem(int userid, int fileid, string dir, string time, int link)
{
    printf("ShareItem\n");

    // 区分文件还是文件夹
    // 查数据库
    char sqlbuf[1024] = "";
    sprintf(sqlbuf, "select f_type,f_name from user_file_info where u_id=%d and f_id=%d and f_dir='%s'", userid, fileid, dir.c_str());
    list<string> lstRes;
    m_sql->SelectMysql(sqlbuf, 2, lstRes);
    if (lstRes.size() == 0)
    {
        return;
    }
    string type = lstRes.front();
    lstRes.pop_front();
    string name = lstRes.front();
    lstRes.pop_front();
    // 分享文件
    ShareFile(userid, fileid, dir, time, link);
    // if (type == "file")
    // {
    //     ShareFile(userid, fileid, dir, time, link);
    // }
    // else
    // {
    //     // 文件夹 路径拼接
    //     ShareFolder(userid, fileid, dir, time, link, name);
    // }
}

void CLogic::ShareFile(int userid, int fileid, string dir, string time, int link)
{
    printf("ShareFile\n");

    char sqlbuf[1024] = "";
    sprintf(sqlbuf, "insert into t_shareFile values(%d,%d,'%s',%d,null,'%s')", userid, fileid, dir.c_str(), link, time.c_str());
    bool res = m_sql->UpdataMysql(sqlbuf);
    if (!res)
    {
        std::cout << "shareFile insert failed" << std::endl;
    }
}
// 分享文件夹时是只对文件夹属性进行分享,获取分享时再递归获取
void CLogic::ShareFolder(int userid, int fileid, string dir, string time, int link, string name)
{
    printf("ShareFolder\n");

    // 当前文件夹 id对应文件共享
    char sqlbuf[1024] = "";
    sprintf(sqlbuf, "insert into t_shareFile values(%d,%d,'%s',%d,null,'%s')", userid, fileid, dir.c_str(), link, time.c_str());
    bool res = m_sql->UpdataMysql(sqlbuf);
    if (!res)
    {
        std::cout << "ShareFolder insert failed" << std::endl;
    }
    // 拼接路径
    string newdir = dir + name + "/";
    // 查路径下的所有文件(夹)
    sprintf(sqlbuf, "select f_id ,f_type,f_name from user_file_info where u_id=%d and f_dir='%s'", userid, newdir.c_str());
    list<string> lstRes;
    m_sql->SelectMysql(sqlbuf, 3, lstRes);
    //  内部包含的文件共享
    // 遍历
    while (lstRes.size() != 0)
    {
        // 根据类型递归
        int fid = stoi(lstRes.front());
        lstRes.pop_front();
        string type = lstRes.front();
        lstRes.pop_front();
        string name = lstRes.front();
        lstRes.pop_front();
        if (type == "file")
        {
            ShareFile(userid, fid, dir, time, link);
        }
        else
        {
            // 文件夹 路径拼接
            ShareFolder(userid, fileid, dir, time, link, name);
        }
    }
}

void CLogic::GetShareByFile(int userid, int fileid, string dir)
{
    // 写入数据库关系表
    char sqlbuf[1024] = "";
    sprintf(sqlbuf, "insert into  t_user_file values(%d,%d,'%s');", userid, fileid, dir.c_str());
    list<string> lstRes;
    m_sql->UpdataMysql(sqlbuf);
}

void CLogic::GetShareByFolder(int userid, int fileid, string dir, int fromuserid, string fromdir, string name)
{
    // 文件夹写关系
    GetShareByFile(userid, fileid, dir);
    // 拼接路径
    // 获取人的,写关系使用
    string newdir = dir + name + "/";
    // 分享人的目录,遍历使用
    string newfromdir = fromdir + name + "/";
    // 查信息
    char sqlbuf[1024] = "";
    string strDir = newdir + name + "/";
    sprintf(sqlbuf, "select f_id , f_name ,f_type from user_file_info where u_id = %d  and f_dir = '%s';", fromuserid, newfromdir.c_str());
    list<string> lstRes;
    m_sql->SelectMysql(sqlbuf, 3, lstRes);
    // 根据文件和文件夹 递归
    while (lstRes.size() != 0)
    {
        int fileid = stoi(lstRes.front());
        lstRes.pop_front();
        string name = lstRes.front();
        lstRes.pop_front();
        string type = lstRes.front();
        lstRes.pop_front();
        if (type == "file")
        {
            GetShareByFile(userid, fileid, newdir);
        }
        else
        {
            GetShareByFolder(userid, fileid, newdir, fromuserid, newfromdir, name);
        }
    }
}

void CLogic::DownloadFolder(int clientfd, int userid, int fileid, string name, string dir)
{
    STRU_FOLDER_HEAD_RQ rq;
    rq.fileid = fileid;

    // printf("newdir:%s\n", newdir.c_str());
    strcpy(rq.dir, dir.c_str());
    strcpy(rq.fileName, name.c_str());
    // 发送下载文件夹
    SendData(clientfd, (char *)&rq, sizeof(rq));
    // 拼接路径
    string newdir = dir + name + "/"; // /1/
    // 查新路径下的文件(夹)
    // 查此文件夹下的文件(夹)
    char sqlbuf[1000] = "";
    sprintf(sqlbuf, "select f_type, t_file.f_id, f_name, f_md5, f_size, t_user_file.f_dir, f_path \
    from t_file inner join t_user_file on t_file.f_id = t_user_file.f_id where t_user_file.u_id = %d and t_user_file.f_dir='%s';",
            userid, newdir.c_str());
    // sprintf(sqlbuf, "select f_type,f_id, f_name, f_md5, f_size, f_dir, f_path from user_file_info where u_id = %d and f_dir = '%s';", rq->userid, rq->dir);

    list<string> lstRes;
    m_sql->SelectMysql(sqlbuf, 7, lstRes);
    if (lstRes.size() == 0)
    {
        // 下载失败
        printf("DownloadFolder failed\n");
        return;
    }
    while (lstRes.size() != 0)
    {
        // 根据类型走不同流程
        if (lstRes.front() == "file")
        {
            DownloadFile(clientfd, userid, lstRes, false);
            // printf("文件:%s\n", newdir.c_str());
        }
        else
        {
            // 文件夹
            string type = lstRes.front();
            lstRes.pop_front();
            int fileid = atoi(lstRes.front().c_str());
            lstRes.pop_front();
            string name = lstRes.front();
            lstRes.pop_front();
            string md5 = lstRes.front();
            lstRes.pop_front();
            int size = atoi(lstRes.front().c_str());
            lstRes.pop_front();
            string dir = lstRes.front();
            lstRes.pop_front();
            string absolutePath = lstRes.front();
            lstRes.pop_front();
            DownloadFolder(clientfd, userid, fileid, name, dir);
        }
    }
}

void CLogic::DownloadFile(int clientfd, int userid, list<string> &lstRes, bool flag)
{
    //  做映射   fileid->FileInfo
    printf("DownloadFile\n");
    FileInfo *info = new FileInfo;
    info->type = lstRes.front();
    lstRes.pop_front();
    info->fileid = atoi(lstRes.front().c_str());
    lstRes.pop_front();
    info->name = lstRes.front();
    lstRes.pop_front();
    info->md5 = lstRes.front();
    lstRes.pop_front();
    info->size = atoi(lstRes.front().c_str());
    lstRes.pop_front();
    info->dir = lstRes.front();
    lstRes.pop_front();
    info->absolutePath = lstRes.front();
    lstRes.pop_front();
    // lstRes.clear();
    info->filefd = open(info->absolutePath.c_str(), O_RDONLY);

    if (info->filefd <= 0)
    {
        std::cout << "file open failed" << info->filefd << std::endl;
    }
    char idbuf[100] = "";
    sprintf(idbuf, "%10d%10d", userid, info->fileid);
    string strid = idbuf;
    m_mapFileidToFileInfo.insert(strid, info);
    STRU_FILE_HEAD_RQ headrq;
    strcpy(headrq.dir, info->dir.c_str()); // 带文件夹的下载，需要dir
    headrq.fileid = info->fileid;
    strcpy(headrq.fileName, info->name.c_str());
    strcpy(headrq.fileType, info->type.c_str());
    strcpy(headrq.md5, info->md5.c_str());
    headrq.size = info->size;
    headrq.flag = false;
    // 返回文件头请求
    SendData(clientfd, (char *)&headrq, sizeof(headrq));
}
